<template>
    <div v-loading="loading" class="console-page">
        <el-form inline :model="searchForm" class="e-page form-item forbid-select" spellcheck="false"
            @submit.native.prevent>
            <el-row class="toolbar">
                <el-col :span="4" style="padding-right: 5px">
                    <el-input v-model="searchForm.name" placeholder="角色名称" clearable class="input-auto-resize" />
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-input v-model="searchForm.description" placeholder="角色描述" clearable class="input-auto-resize" />
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-select v-model="searchForm.status" clearable placeholder="请选择状态" class="input-auto-resize">
                        <el-option v-for="item in statusSelect" :key="item.value" :label="item.label"
                            :value="item.value" />
                    </el-select>
                </el-col>
                <el-col :span="4" style="padding-right: 5px">
                    <el-button type="primary" @click="searchTable" circle :icon="getIcon('search')"
                        :loading="bt_loading" class="button-auto-resize" native-type="submit" />
                </el-col>
                <el-col :span="8" style="text-align: right" v-permission="$permission.Write | $permission.Execute">
                    <el-button type="danger" :icon="getIcon('SwitchButton')" circle class="button-auto-resize"
                        @click="offline()" confirmTitle="确定下线所有角色?" v-permission="$permission.Execute" />
                    <el-button :icon="getIcon('plus')" circle class="button-auto-resize" @click="openDialog('new')"
                        v-permission="$permission.Write" />
                </el-col>
            </el-row>
        </el-form>
        <el-table :data="tableData" border header-cell-class-name="el-table-header-cell" cell-class-name="el-table-cell"
            class="e-page table-with-pagination" highlight-current-row>
            <el-table-column prop="name" label="角色名称" min-width="150" />
            <el-table-column prop="description" label="角色描述" min-width="150" />
            <el-table-column prop="interfaceVip" label="接口白名单" :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <!-- 状态 -->
                    <el-tag :type="scope.row.interfaceVip === 1 ? 'success' : 'info'" class="input-auto-resize"
                        disable-transitions>{{
                            scope.row.interfaceVip === 1 ? '是' : '否' }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="status" label="状态" :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <!-- 状态 -->
                    <el-tag :type="scope.row.status === '1' ? 'primary' : 'danger'" class="input-auto-resize"
                        disable-transitions>
                        {{ scope.row.status === '1' ? '正常' : '禁用' }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="creator" label="创建人" min-width="120" />
            <el-table-column prop="crtTime" label="创建时间" :width="fontAutoResize.size_11.value" />
            <el-table-column prop="updateTime" label="更新时间" :width="fontAutoResize.size_11.value" />
            <el-table-column label="操作" :width="operationWidth" className="operation-column"
                v-permission="$permission.Update | $permission.Execute">
                <template #default="scope">
                    <el-button :disabled="checkDisable(scope)" @click="forbidStatus(scope.$index, tableData)"
                        type="danger" circle :icon="scope.row.status === 1 ? getIcon('lock') : getIcon('unlock')"
                        class="button-auto-resize" v-permission="$permission.Update" />
                    <el-button @click="changeVip(scope.$index, tableData)"
                        :type="scope.row.interfaceVip === 1 ? 'success' : 'info'" circle :icon="getIcon('Star')"
                        class="button-auto-resize" v-permission="$permission.Update" />
                    <el-button :disabled="checkDisable(scope)" type="primary" :icon="getIcon('editPen')" circle
                        class="button-auto-resize" @click="openDialog(scope.$index, tableData)"
                        v-permission="$permission.Update" />
                    <el-button :disabled="scope.row.name === admin.role" type="primary" :icon="getIcon('link')" circle
                        class="button-auto-resize" @click="openRoleMenuDialog(scope.$index, tableData)"
                        v-permission="$permission.Update" />
                    <el-button type="danger" :icon="getIcon('SwitchButton')" circle class="button-auto-resize"
                        @click="offline(scope.row.name)" :confirmTitle="`确定下线所有 ${scope.row.name} 角色?`"
                        v-permission="$permission.Execute" />
                </template>
            </el-table-column>
        </el-table>
        <div style="height: 50px;">
            <el-pagination background @size-change="SizeChange" @current-change="CurrentChange"
                :current-page="currentPage" :page-sizes="page_sizes" :page-size="page_size"
                layout="total, sizes, prev, pager, next, jumper" prev-text="<上一页" next-text="下一页>" :total="total"
                class="e-page">
            </el-pagination>
        </div>
        <el-dialog title="角色信息" v-model="roleInfoVisible" @close="clearUserForm" :show-close="false" width="50%"
            append-to-body class="roleMenu-dialog">
            <el-form :model="roleInfo" status-icon ref="roleInfoRef" class="e-page form-auto-resize" spellcheck="false"
                @submit.native.prevent>
                <el-form-item label="角色名称" prop="name" :rules="[{ required: true, message: '请输入角色名称', trigger: [] }]">
                    <tooltip v-if="SuperRoleDisable || opType === 'modify'" v-model="roleInfo.name" border />
                    <el-input v-model="roleInfo.name" autocomplete="off" class="input-auto-resize" v-else />
                </el-form-item>
                <el-form-item label="角色描述" prop="description"
                    :rules="[{ required: true, message: '请输入角色描述', trigger: [] }]">
                    <el-input v-model="roleInfo.description" autocomplete="off" class="input-auto-resize"
                        :disabled="SuperRoleDisable" />
                </el-form-item>
            </el-form>

            <template #footer>
                <span>
                    <el-button @click="roleInfoVisible = !roleInfoVisible" :icon="getIcon('close')" circle
                        class="button-auto-resize" />
                    <el-button type="primary" @click="submitRoleData" :icon="getIcon('check')" circle
                        class="button-auto-resize" :disabled="SuperRoleDisable" :loading="submit_loading" />
                </span>
            </template>
        </el-dialog>
        <el-dialog title="角色目录信息" v-model="roleMenuVisible" @closed="roleMenuclose" append-to-body
            class="forbid-select roleMenuDialog roleMenu-dialog" :close-on-press-escape="false" width="50%" top="10vh"
            :close-on-click-modal="false" :show-close="false" @open="roleMenuOpen" @opened="roleMenuOpened">
            <el-form :model="roleMenuForm" status-icon ref="roleMenuRef" class="form-auto-resize" spellcheck="false">
                <el-form-item label="角色名称" prop="name" class="el-form-line">
                    <tooltip v-model="roleMenuForm.role" border />
                </el-form-item>
                <div style="display: flex;" class="el-form-line">
                    <el-form-item label="显示方式" prop="type">
                        <el-switch v-model="menuShowType" active-value="1" inactive-value="0" active-text="目录优先"
                            inactive-text="权限优先" inline-prompt class="fit-auto-resize" :disabled="disable"
                            style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" />
                    </el-form-item>
                    <el-form-item label="当前已选择目录数" prop="number" label-width="180px">
                        <div>{{ onlyMenuNum.toFixed(0) }}</div>
                    </el-form-item>
                    <el-form-item label="当前已选择权限数" prop="number" label-width="180px">
                        <div>{{ permissionNum.toFixed(0) }}</div>
                    </el-form-item>
                </div>

                <el-form-item label="角色目录" prop="description" class="el-form-line">
                    <el-cascader-panel style="width: 100%" class="roleMenu forbid-select" :disabled="SuperRoleDisable"
                        v-model="roleMenuForm.selectData" ref="cascaderRef" :options="showMenuData" :props="props"
                        @node-click="nodeClick">
                        <template #default="{ node, data }">
                            <span :class="getNodeClass(node, data)">
                                {{ data.label }}
                            </span>
                        </template>
                    </el-cascader-panel>
                </el-form-item>
            </el-form>

            <template #footer>
                <el-button @click="toggleSelect" class="fit-auto-resize toggle">
                    {{ allChecked ? '取消全选' : '全选' }}
                </el-button>
                <el-button @click="roleMenuVisible = !roleMenuVisible" :icon="getIcon('close')" circle
                    class="button-auto-resize" />
                <el-button type="primary" @click="submitRoleMenuData" :icon="getIcon('check')" circle
                    :disabled="SuperRoleDisable" :loading="submit_loading" class="button-auto-resize" />
            </template>
        </el-dialog>
    </div>
</template>
<script setup>
import { admin } from "@/utils/constant"
import { useElMessage, useSetTableOperationWidth, useElLoading, useModalSize, useRequest } from "@usehook"
import { fontAutoResize } from "@/utils/setting"
import { deepCopy, getIcon } from "@/utils/tools"
import { useTransition } from '@vueuse/core'

const operationWidth = useSetTableOperationWidth(5)

let tableData = $ref([])//role表格信息
let currentPage = $ref(1)
let page_size = $ref(0)
let total = $ref(0)
let statusSelect = [{ value: 1, label: '正常' }, { value: 0, label: '禁用' }]
let roleInfoVisible = $ref(false)
let roleInfo = $ref({
    sequence: '',
    name: '',
    description: '',
})
let searchForm = $ref({
    name: '',
    description: '',
    status: 1
})
let loading = $ref(false)
let bt_loading = $ref(false)
let SuperRoleDisable = $ref(false)
let page_sizes = [10, 30, 50, 100, 200]
let opType = $ref('new')
let submit_loading = $ref(false)
const roleInfoRef = $ref(null)
const roleMenuRef = $ref(null)
let roleMenuForm = $ref({ role: '', selectData: [] })
let menuData = $ref([])  //role所有目录信息
let permissionList = $ref([])
let selectMenu = $ref({})//role和menu的关系
let props = { multiple: true, expandTrigger: 'click' }
let roleMenuVisible = $ref(false)
const cascaderRef = $ref(null)
let menuShowType = $ref("1")
let disable = $ref(false)
const animateClass = ["animate__animated", "animate__fadeInLeft", "animate__fast"]
let timeout = $ref(null)

const offline = (role) => {
    useRequest.post({ url: "/user/offline", role }).then((resp) => {
        console.log(resp)
    })
}

const permissionNum = useTransition(() => roleMenuForm.selectData.length, {
    duration: 500,
    transition: [0.75, 0, 0.25, 1],
})

const onlyMenuNum = useTransition(() => Array.from(new Set(menuShowType === '1' ? roleMenuForm.selectData.map(e => e[1]) : roleMenuForm.selectData.map(e => e[2]))).length, {
    duration: 500,
    transition: [0.75, 0, 0.25, 1],
})

const getNodeClass = (node, data) => {
    const c1 = data.status && data.status !== 1 ? 'not-show' : ''
    const c2 = node.level === 3 ? `last-cascader` : ""
    const c3 = `cascader-node-level-${node.level}`
    return `${c1} ${c2} ${c3}`
}

const toggleSelect = () => {
    nextTick(() => {
        for (let ele of cascaderRef.$el.querySelectorAll(".animate__animated")) {
            ele.classList.remove(...animateClass)
        }
        nextTick(() => {
            for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
                ele.style.display = "block"
                ele.classList.add(...animateClass)
            }
            clearTimeout(timeout)
            timeout = setTimeout(() => {
                for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
                    ele.classList.remove(...animateClass)
                }
            }, 500)
        })
    })
    cascaderRef.toggleAllCheckedMenu()
    disable = true
}

let currentNodeId = $ref("")

const nodeClick = (nodeInfo) => {
    if (nodeInfo.type === 'select') disable = true
    for (let ele of cascaderRef.$el.querySelectorAll(".animate__animated")) {
        // if (ele.getAttribute("menuid") === nodeInfo.menuId || nodeInfo.node.level >= ele.getAttribute("level")) continue
        if (currentNodeId === nodeInfo.nodeId) continue
        ele.classList.remove(...animateClass)
    }
    for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
        if (parseInt(ele.getAttribute("level")) - nodeInfo.node.level > 1) {
            ele.style.display = "none"
        } else {
            ele.style.display = "block"
        }
    }
    nextTick(() => {
        const currentEle = cascaderRef.$el.querySelector(`[menuid="${nodeInfo.menuId}"]`)
        const allEle = Array.from(cascaderRef.$el.querySelectorAll(".el-cascader-menu"))
        const nextEle = allEle[allEle.indexOf(currentEle) + 1]
        if (nextEle) {
            nextEle.classList.add(...animateClass)
        }
    })
    currentNodeId = nodeInfo.nodeId
}

const roleMenuOpen = () => {
    for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
        ele.classList.add(...animateClass)
    }
}

const roleMenuOpened = () => {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
        for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
            ele.classList.remove(...animateClass)
        }
    }, 500)
}

const allChecked = computed(() => {
    return cascaderRef ? cascaderRef.getFlattedNodes(true).length === cascaderRef.checkedNodes.length : false
})

let showMenuData = $ref([])

watch(() => menuShowType, () => {
    nextTick(() => {
        for (let ele of cascaderRef.$el.querySelectorAll(".animate__animated")) {
            ele.classList.remove(...animateClass)

        }
        nextTick(() => {
            for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
                ele.style.display = "block"
                ele.classList.add(...animateClass)
            }
            clearTimeout(timeout)
            timeout = setTimeout(() => {
                for (let ele of cascaderRef.$el.querySelectorAll(".el-cascader-menu")) {
                    ele.classList.remove(...animateClass)
                }
            }, 500)
        })
    })
})

watchEffect(() => {
    if (!roleMenuForm.role || !roleMenuVisible) return
    const selectData = deepCopy(selectMenu[roleMenuForm.role]) || []

    if (menuShowType === '1') {
        showMenuData = deepCopy(menuData)
        const copyPermissionList = deepCopy(permissionList)
        roleMenuForm.selectData = selectData
        for (let menu of showMenuData) {
            for (let children of menu.children) {
                children['children'] = copyPermissionList
            }
        }
    } else {
        roleMenuForm.selectData = selectData.map(e => {
            return [e[2], e[0], e[1]]
        })

        showMenuData = deepCopy(permissionList)
        const copyMenuData = deepCopy(menuData)

        for (let permission of showMenuData) {
            permission['children'] = copyMenuData
        }
    }
})

const getRole = (params) => {
    loading = true
    bt_loading = true
    useRequest({ url: "/user/role/getData", ...params }).then(resp => {
        if (resp.status) { //0表示成功，1表示失败
            tableData = resp.data
            total = resp.totalRecord
        } else if (resp.message) useElMessage(resp.message)
    }).finally(_ => {
        loading = false
        bt_loading = false
    })
}

const modifyRole = (roleInfo) => {
    submit_loading = true
    useRequest({ method: "post", ...roleInfo }).then(resp => {
        if (resp.status) { //0表示成功，1表示失败
            if (resp.message) useElMessage(resp.message)
            refreshTable()
        } else {
            if (resp.message) useElMessage.error(resp.message)
        }
    }).finally(_ => {
        submit_loading = false
    })
}

const clearValidate = () => {
    if (roleInfoRef) {
        roleInfoRef.clearValidate()
    }
}

const clearUserForm = () => {
    useModalSize(false)
    setTimeout(() => {
        for (let i in roleInfo) {
            roleInfo[i] = ''
        }
        SuperRoleDisable = false
    }, 500)
}

const searchTable = () => {
    getRole({
        'search': JSON.stringify(searchForm),
        'limit': page_size,
        'page': 1
    })
    currentPage = 1
    getselectMenu()
}

const refreshTable = () => {
    setTimeout(() => {
        getRole({
            'search': JSON.stringify(searchForm),
            'limit': page_size,
            'page': currentPage
        })
    }, 10)
}

const submitRoleData = () => {
    roleInfoRef.validate((valid) => {
        if (valid) {
            modifyRole({ role: roleInfo, url: '/user/role/modify' })
            roleInfoVisible = false
        } else {
            return false
        }
    })
}

const { loading: elLoading, close } = useElLoading({ text: "正在配置角色权限信息", target: ".roleMenuDialog", manual: true, delay: 10 })

const submitRoleMenuData = () => {
    const roleMenuData = deepCopy(roleMenuForm)
    roleMenuData.selectData = roleMenuData.selectData.map(e => {
        return menuShowType === '1' ? e : [e[1], e[2], e[0]]
    })
    roleMenuRef.validate((valid) => {
        if (valid) {
            submit_loading = true
            elLoading()
            useRequest({ method: "post", roleMenu: roleMenuData, url: '/user/role/roleMenu' }).then(resp => {
                if (resp.status) { //0表示成功，1表示失败
                    if (resp.message) useElMessage(resp.message)
                    roleMenuVisible = false
                    getselectMenu()
                } else {
                    if (resp.message) useElMessage.error(resp.message)
                }
            }).finally(() => {
                submit_loading = false
                close()
            })
        } else {
            return false
        }
    })
}

const forbidStatus = (index, rows) => {
    //防止当前页面为空页码不跳
    if (total - 1 === (currentPage - 1) * page_size && total !== 1 && searchForm.status) {
        currentPage -= 1
    }

    let roleInfo = rows[index]
    if (roleInfo) {
        modifyRole({ sequence: roleInfo.sequence, url: '/user/role/forbid' })
    }
}

const changeVip = (index, rows) => {
    //防止当前页面为空页码不跳
    if (total - 1 === (currentPage - 1) * page_size && total !== 1 && searchForm.status) {
        currentPage -= 1
    }

    let roleInfo = rows[index]
    if (roleInfo) {
        modifyRole({ sequence: roleInfo.sequence, url: '/user/role/changeVip' })
    }
}

const openDialog = (index, rows) => {
    clearValidate()
    useModalSize()
    if (index !== 'new') {
        opType = 'modify'
        let _roleInfo = rows[index]
        if (_roleInfo != null) {
            roleInfo.sequence = _roleInfo.sequence
            roleInfo.name = _roleInfo.name
            roleInfo.description = _roleInfo.description
        }
        if (roleInfo.name === admin.role) {
            SuperRoleDisable = true
        }
    } else {
        opType = 'new'
    }
    roleInfoVisible = true
}

const SizeChange = (val) => {
    getRole({
        'search': JSON.stringify(searchForm),
        'limit': val,
        'page': currentPage
    })
    page_size = val
}

const CurrentChange = (val) => {
    getRole({
        'search': JSON.stringify(searchForm),
        'limit': page_size,
        'page': val
    })
    currentPage = val
}

const checkDisable = (scope) => {
    return scope.row.name === admin.role || scope.row.name === 'normal'
}

const openRoleMenuDialog = (index, rows) => {
    useModalSize()
    let roleInfo = rows[index]
    if (roleInfo != null) {
        roleMenuForm.role = roleInfo.name
    }
    if (roleInfo.name === admin.role) {
        SuperRoleDisable = true
    }
    roleMenuVisible = true
}

const getMenuData = () => {
    useRequest({ url: "/user/role/menuData", }).then(resp => {
        if (resp.status) { //0表示成功，1表示失败
            menuData = resp.data.menu.filter(e => e.value !== "/")
            permissionList = resp.data.permission
        } else if (resp.message) useElMessage(resp.message)
    })
}

const getselectMenu = () => {
    useRequest({ url: "/user/role/selectMenu", }).then(resp => {
        if (resp.status) { //0表示成功，1表示失败
            selectMenu = resp.data
        } else if (resp.message) useElMessage(resp.message)
    })
}

const roleMenuclose = () => {
    useModalSize(false)
    roleMenuForm = { role: '', selectData: [] }
    disable = false
}

onMounted(() => {
    page_size = page_sizes[1]
    getRole({
        'search': JSON.stringify(searchForm),
        'limit': page_size,
        'page': currentPage
    })
    getMenuData()
    getselectMenu()
})
</script>
<style scoped>
:deep(.el-form-item__error) {
    padding-top: 0
}
</style>

<style lang="scss">
.roleMenu-dialog.el-dialog .el-form-item__error {
    top: 13px;
    right: 35px;
    left: unset;
}

.roleMenu-dialog.el-dialog .el-dialog__body {
    padding: 10px !important;
}

.roleMenu-dialog.el-dialog .el-dialog__header {
    border-bottom: 1px solid #e4e7ec;
}

.roleMenu-dialog.el-dialog .el-dialog__footer {
    padding: 10px;
    border-top: 1px solid #e4e7ec;
}

.roleMenu-dialog.el-dialog .el-dialog__body .el-form-item {
    margin-bottom: 0;
}

.roleMenu-dialog.el-dialog .el-dialog__body .el-form-item+.el-form-item {
    margin-top: 15px;
    margin-bottom: 0;
}

.roleMenu .el-cascader-node.in-active-path {
    background: rgb(107 158 255 / 15%);
}

.roleMenu.el-cascader-panel .el-cascader-menu .el-cascader-node.is-select {
    background: rgb(107 158 255 / 15%) !important
}

.roleMenu.el-cascader-panel {
    // font-size: var(--font-size);
    height: calc(34px * 9);
}

.roleMenu .el-cascader-menu__wrap.el-scrollbar__wrap {
    height: 100%;
}

.roleMenu .el-cascader-menu {
    min-width: calc(100% / 3) !important;
    border-right: var(--el-cascader-menu-border);
}

.roleMenu .el-cascader-menu:nth-child(3) {
    border-right: none;
}

.roleMenu .el-cascader-node__label {
    padding-right: 5px !important;

    span {
        display: block;
        width: 100%;
        height: 100%;
    }
}

.roleMenu .el-cascader-menu:last-child .el-cascader-node {
    padding-right: 5px !important;
}

.el-cascader-node.in-active-path,
.el-cascader-node.is-active,
.el-cascader-node.is-selectable.in-checked-path {
    font-weight: normal
}

.in-active-path .not-show {
    color: rgb(86 144 204 / 75%)
}

.not-show {
    color: #bfbfbf
}

.roleMenuDialog {
    .el-form-item {
        padding: 0 !important;
        margin: 0 !important;
    }

    .el-form-line {
        width: 100% !important;
    }

    .el-form-line+.el-form-line {
        padding-top: 10px !important;
    }

    .el-loading-spinner .el-loading-text {
        color: rgb(255 0 0);
        font-size: 16px;
        margin: 3px 0;
    }

    .el-button+.el-button {
        margin-left: 10px !important;
    }

    .toggle {
        width: 100px !important;
        position: absolute;
        left: 10px;
    }
}

.roleMenu.el-cascader-panel.is-bordered {
    border: 1px solid var(--el-input-border-color, var(--el-border-color));
    // box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
}

.roleMenu .el-cascader-menu__list {
    padding: 0;
}

.roleMenu .el-cascader-node:not(.is-disabled) {
    cursor: default;
}
</style>